﻿using Ormon.HostLinkLib.CmodeBase;
using Ormon.HostLinkLib.HostLinkBase;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ormon.HostLinkLib
{
    public class HostLinkCmodeDevice
    {
        //串口示例
        private SerialPort serialPort;
        public string PortName;

        /// <summary>
        /// 构造函数——HostLinkCmodeDevice
        /// </summary>
        /// <param name="portName">端口名</param>
        /// <param name="baudRate">波特率</param>
        /// <param name="parity">奇偶校验</param>
        /// <param name="dataBits">数据位</param>
        /// <param name="stopBits">停止位</param>
        public HostLinkCmodeDevice(string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits)
        {
            serialPort = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
            PortName = serialPort.PortName;
        }

        /// <summary>
        /// 端口开启
        /// </summary>
        public void Connect()
        {
            try
            {
                serialPort.Open();
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 端口关闭
        /// </summary>
        public void DisConnect()
        {
            try
            {
                serialPort.Close();
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 将int转换成4位字节数组
        /// </summary>
        /// <param name="IntValue">输入的int数值</param>
        /// <returns>转换得到的字节数组</returns>
        private static List<byte> Int_D4String_ByteList(int IntValue)
        {
            string StringValue = IntValue.ToString("D4");

            return Encoding.ASCII.GetBytes(StringValue).ToList();
        }


        #region 同步方法


        /// <summary>
        /// 发送测试内容
        /// </summary>
        /// <param name="TestContent">发送的内容</param>
        /// <param name="UnitNO">单元号（00—32）</param>
        /// <returns>返回相同的发送内容或者返回结束代码</returns>
        public string TestCommand(string TestContent, string UnitNO = "00")
        {
            try
            {
                List<byte> CommandFrame = new List<byte> { 0x40 };
                List<byte> ResponseFrame = new List<byte>();
                CommandFrame.AddRange(ASCIIEncoding.ASCII.GetBytes(UnitNO));
                CommandFrame.AddRange(CmodeHeaderCode.HeaderCode_TS);
                if (TestContent != string.Empty && TestContent != null)
                {
                    //增加读取内容
                    CommandFrame.AddRange(ASCIIEncoding.ASCII.GetBytes(TestContent));
                }
                else
                {
                    throw new Exception("未输入内容");
                }
                //增加结束符，完成命令报文
                CommandFrame.AddRange(HostLinkCore.HostLinkEndCode(CommandFrame));

                //获取回复报文
                ResponseFrame = HostLinkCore.HostLinkCommCore(serialPort, CommandFrame);

                return ASCIIEncoding.ASCII.GetString(ResponseFrame.ToArray());
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 获取PLC运行状态
        /// </summary>
        /// <param name="UnitNO">单元号（00—32）</param>
        /// <returns>返回读取得到的结果（十六进制数）或者返回结束代码</returns>
        public string PLCStatus_Read(string UnitNO = "00")
        {
            try
            {
                string EndCodeContent = null;
                string ResponseData = null;
                List<byte> CommandFrame = new List<byte> { 0x40 };
                List<byte> ResponseFrame = new List<byte>();
                List<byte> ResponseDataFrame = new List<byte>();
                CommandFrame.AddRange(ASCIIEncoding.ASCII.GetBytes(UnitNO));
                CommandFrame.AddRange(CmodeHeaderCode.HeaderCode_MS);
                //增加结束符，完成命令报文
                CommandFrame.AddRange(HostLinkCore.HostLinkEndCode(CommandFrame));

                //获取回复报文
                ResponseFrame = HostLinkCore.HostLinkCommCore(serialPort, CommandFrame);

                //获取结束代码
                EndCodeContent = CmodeEndCode.CatchEndCode(ResponseFrame, 5);
                if (EndCodeContent.Equals("00"))
                {
                    ResponseDataFrame = ResponseFrame.GetRange(7, ResponseFrame.Count - 11);
                    ResponseData = ASCIIEncoding.ASCII.GetString(ResponseDataFrame.ToArray());
                    return ResponseData;
                }
                else
                {
                    return EndCodeContent;
                }
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 改变PLC运行状态
        /// </summary>
        /// <param name="WriteData">写入的数值（十六进制）</param>
        /// <param name="UnitNO">单元号（00—32）</param>
        /// <returns>返回结束代码</returns>
        public string PLCStatus_Change(string WriteData, string UnitNO = "00")
        {
            try
            {
                string EndCodeContent = null;
                List<byte> CommandFrame = new List<byte> { 0x40 };
                List<byte> ResponseFrame = new List<byte>();
                CommandFrame.AddRange(ASCIIEncoding.ASCII.GetBytes(UnitNO));
                CommandFrame.AddRange(CmodeHeaderCode.HeaderCode_SC);
                if (WriteData != string.Empty && WriteData != null)
                {
                    //增加写入内容
                    CommandFrame.AddRange(ASCIIEncoding.ASCII.GetBytes(WriteData));
                }
                else
                {
                    throw new Exception("未输入数值");
                }
                //增加结束符，完成命令报文
                CommandFrame.AddRange(HostLinkCore.HostLinkEndCode(CommandFrame));

                //获取回复报文
                ResponseFrame = HostLinkCore.HostLinkCommCore(serialPort, CommandFrame);

                //获取结束代码
                EndCodeContent = CmodeEndCode.CatchEndCode(ResponseFrame, 5);
                return EndCodeContent;
            }
            catch (Exception)
            {
                throw;
            }
        }




        /// <summary>
        /// 读取CIO内存区域
        /// </summary>
        /// <param name="BeginAdr">读取开始地址值（十进制）</param>
        /// <param name="ReadCount">读取的数量（十进制）</param>
        /// <param name="UnitNO">单元号（00—32）</param>
        /// <returns>返回读取得到的结果（十六进制数）或者返回结束代码</returns>
        public string Read_CIOArea(int BeginAdr, int ReadCount, string UnitNO = "00")
        {
            try
            {
                string EndCodeContent = null;
                string ResponseData = null;
                List<byte> CommandFrame = new List<byte> { 0x40 };
                List<byte> ResponseFrame = new List<byte>();
                List<byte> ResponseDataFrame = new List<byte>();
                CommandFrame.AddRange(ASCIIEncoding.ASCII.GetBytes(UnitNO));
                CommandFrame.AddRange(CmodeHeaderCode.HeaderCode_RR);
                //增加读取地址
                CommandFrame.AddRange(Int_D4String_ByteList(BeginAdr));
                //增加读取内容
                CommandFrame.AddRange(Int_D4String_ByteList(ReadCount));
                //增加结束符，完成命令报文
                CommandFrame.AddRange(HostLinkCore.HostLinkEndCode(CommandFrame));

                //获取回复报文
                ResponseFrame = HostLinkCore.HostLinkCommCore(serialPort, CommandFrame);

                //获取结束代码
                EndCodeContent = CmodeEndCode.CatchEndCode(ResponseFrame, 5);
                if (EndCodeContent.Equals("00"))
                {
                    ResponseDataFrame = ResponseFrame.GetRange(7, ResponseFrame.Count - 11);
                    ResponseData = ASCIIEncoding.ASCII.GetString(ResponseDataFrame.ToArray());
                    return ResponseData;
                }
                else
                {
                    return EndCodeContent;
                }
            }
            catch (Exception)
            {
                throw;
            }
        }


        /// <summary>
        /// 读取DM内存区域
        /// </summary>
        /// <param name="BeginAdr">读取开始地址值（十进制）</param>
        /// <param name="ReadCount">读取的数量（十进制）</param>
        /// <param name="UnitNO">单元号（00—32）</param>
        /// <returns>返回读取得到的结果（十六进制数）或者返回结束代码</returns>
        public string Read_DMArea(int BeginAdr, int ReadCount, string UnitNO = "00")
        {
            try
            {
                string EndCodeContent = null;
                string ResponseData = null;
                List<byte> CommandFrame = new List<byte> { 0x40 };
                List<byte> ResponseFrame = new List<byte>();
                List<byte> ResponseDataFrame = new List<byte>();
                CommandFrame.AddRange(ASCIIEncoding.ASCII.GetBytes(UnitNO));
                CommandFrame.AddRange(CmodeHeaderCode.HeaderCode_RD);
                //增加读取地址
                CommandFrame.AddRange(Int_D4String_ByteList(BeginAdr));
                //增加读取内容
                CommandFrame.AddRange(Int_D4String_ByteList(ReadCount));
                //增加结束符，完成命令报文
                CommandFrame.AddRange(HostLinkCore.HostLinkEndCode(CommandFrame));

                //获取回复报文
                ResponseFrame = HostLinkCore.HostLinkCommCore(serialPort, CommandFrame);

                //获取结束代码
                EndCodeContent = CmodeEndCode.CatchEndCode(ResponseFrame, 5);
                if (EndCodeContent.Equals("00"))
                {
                    ResponseDataFrame = ResponseFrame.GetRange(7, ResponseFrame.Count - 11);
                    ResponseData = ASCIIEncoding.ASCII.GetString(ResponseDataFrame.ToArray());
                    return ResponseData;
                }
                else
                {
                    return EndCodeContent;
                }
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 写入CIO内存区域
        /// </summary>
        /// <param name="BeginAdr">读取开始地址值（十进制）</param>
        /// <param name="WriteData">写入的数值（十六进制）</param>
        /// <param name="UnitNO">单元号（00—32）</param>
        /// <returns>返回结束代码</returns>
        public string Write_CIOArea(int BeginAdr, string WriteData, string UnitNO = "00")
        {
            try
            {
                string EndCodeContent = null;
                List<byte> CommandFrame = new List<byte> { 0x40 };
                List<byte> ResponseFrame = new List<byte>();
                CommandFrame.AddRange(ASCIIEncoding.ASCII.GetBytes(UnitNO));
                CommandFrame.AddRange(CmodeHeaderCode.HeaderCode_WR);
                //增加读取地址
                CommandFrame.AddRange(Int_D4String_ByteList(BeginAdr));
                if (WriteData != string.Empty && WriteData != null)
                {
                    //增加写入内容
                    CommandFrame.AddRange(ASCIIEncoding.ASCII.GetBytes(WriteData));
                }
                else
                {
                    throw new Exception("未输入数值");
                }
                //增加结束符，完成命令报文
                CommandFrame.AddRange(HostLinkCore.HostLinkEndCode(CommandFrame));

                //获取回复报文
                ResponseFrame = HostLinkCore.HostLinkCommCore(serialPort, CommandFrame);

                //获取结束代码
                EndCodeContent = CmodeEndCode.CatchEndCode(ResponseFrame, 5);
                return EndCodeContent;
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 写入DM内存区域
        /// </summary>
        /// <param name="BeginAdr">读取开始地址值（十进制）</param>
        /// <param name="WriteData">写入的数值（十六进制）</param>
        /// <param name="UnitNO">单元号（00—32）</param>
        /// <returns>返回结束代码</returns>
        public string Write_DMArea(int BeginAdr, string WriteData, string UnitNO = "00")
        {
            try
            {
                string EndCodeContent = null;
                List<byte> CommandFrame = new List<byte> { 0x40 };
                List<byte> ResponseFrame = new List<byte>();
                CommandFrame.AddRange(ASCIIEncoding.ASCII.GetBytes(UnitNO));
                CommandFrame.AddRange(CmodeHeaderCode.HeaderCode_WD);
                //增加读取地址
                CommandFrame.AddRange(Int_D4String_ByteList(BeginAdr));
                if (WriteData != string.Empty && WriteData != null)
                {
                    //增加写入内容
                    CommandFrame.AddRange(ASCIIEncoding.ASCII.GetBytes(WriteData));
                }
                else
                {
                    throw new Exception("未输入数值");
                }
                //增加结束符，完成命令报文
                CommandFrame.AddRange(HostLinkCore.HostLinkEndCode(CommandFrame));

                //获取回复报文
                ResponseFrame = HostLinkCore.HostLinkCommCore(serialPort, CommandFrame);

                //获取结束代码
                EndCodeContent = CmodeEndCode.CatchEndCode(ResponseFrame, 5);
                return EndCodeContent;
            }
            catch (Exception)
            {
                throw;
            }
        }


        #endregion



        #region 异步方法


        /// <summary>
        /// 发送测试内容（异步方法）
        /// </summary>
        /// <param name="TestContent">发送的内容</param>
        /// <param name="UnitNO">单元号（00—32）</param>
        /// <returns>返回相同的发送内容或者返回结束代码</returns>
        public async Task<string> TestCommandAsync(string TestContent, string UnitNO = "00")
        {
            try
            {
                List<byte> CommandFrame = new List<byte> { 0x40 };
                List<byte> ResponseFrame = new List<byte>();
                CommandFrame.AddRange(ASCIIEncoding.ASCII.GetBytes(UnitNO));
                CommandFrame.AddRange(CmodeHeaderCode.HeaderCode_TS);
                if (TestContent != string.Empty && TestContent != null)
                {
                    //增加读取内容
                    CommandFrame.AddRange(ASCIIEncoding.ASCII.GetBytes(TestContent));
                }
                else
                {
                    throw new Exception("未输入内容");
                }
                //增加结束符，完成命令报文
                CommandFrame.AddRange(HostLinkCore.HostLinkEndCode(CommandFrame));

                //获取回复报文
                ResponseFrame = await HostLinkCore.HostLinkCommCoreAsync(serialPort, CommandFrame);

                return ASCIIEncoding.ASCII.GetString(ResponseFrame.ToArray());
            }
            catch (Exception)
            {
                throw;
            }
        }


        /// <summary>
        /// 获取PLC运行状态（异步方法）
        /// </summary>
        /// <param name="UnitNO">单元号（00—32）</param>
        /// <returns>返回读取得到的结果（十六进制数）或者返回结束代码</returns>
        public async Task<string> PLCStatus_ReadAsync(string UnitNO = "00")
        {
            try
            {
                string EndCodeContent = null;
                string ResponseData = null;
                List<byte> CommandFrame = new List<byte> { 0x40 };
                List<byte> ResponseFrame = new List<byte>();
                List<byte> ResponseDataFrame = new List<byte>();
                CommandFrame.AddRange(ASCIIEncoding.ASCII.GetBytes(UnitNO));
                CommandFrame.AddRange(CmodeHeaderCode.HeaderCode_MS);
                //增加结束符，完成命令报文
                CommandFrame.AddRange(HostLinkCore.HostLinkEndCode(CommandFrame));

                //获取回复报文
                ResponseFrame = await HostLinkCore.HostLinkCommCoreAsync(serialPort, CommandFrame);

                //获取结束代码
                EndCodeContent = CmodeEndCode.CatchEndCode(ResponseFrame, 5);
                if (EndCodeContent.Equals("00"))
                {
                    ResponseDataFrame = ResponseFrame.GetRange(7, ResponseFrame.Count - 11);
                    ResponseData = ASCIIEncoding.ASCII.GetString(ResponseDataFrame.ToArray());
                    return ResponseData;
                }
                else
                {
                    return EndCodeContent;
                }
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 改变PLC运行状态（异步方法）
        /// </summary>
        /// <param name="WriteData">写入的数值（十六进制）</param>
        /// <param name="UnitNO">单元号（00—32）</param>
        /// <returns>返回结束代码</returns>
        public async Task<string> PLCStatus_ChangeAsync(string WriteData, string UnitNO = "00")
        {
            try
            {
                string EndCodeContent = null;
                List<byte> CommandFrame = new List<byte> { 0x40 };
                List<byte> ResponseFrame = new List<byte>();
                CommandFrame.AddRange(ASCIIEncoding.ASCII.GetBytes(UnitNO));
                CommandFrame.AddRange(CmodeHeaderCode.HeaderCode_SC);
                if (WriteData != string.Empty && WriteData != null)
                {
                    //增加写入内容
                    CommandFrame.AddRange(ASCIIEncoding.ASCII.GetBytes(WriteData));
                }
                else
                {
                    throw new Exception("未输入数值");
                }
                //增加结束符，完成命令报文
                CommandFrame.AddRange(HostLinkCore.HostLinkEndCode(CommandFrame));

                //获取回复报文
                ResponseFrame = await HostLinkCore.HostLinkCommCoreAsync(serialPort, CommandFrame);

                //获取结束代码
                EndCodeContent = CmodeEndCode.CatchEndCode(ResponseFrame, 5);
                return EndCodeContent;
            }
            catch (Exception)
            {
                throw;
            }
        }


        /// <summary>
        /// 读取CIO内存区域（异步方法）
        /// </summary>
        /// <param name="BeginAdr">读取开始地址值（十进制）</param>
        /// <param name="ReadCount">读取的数量（十进制）</param>
        /// <param name="UnitNO">单元号（00—32）</param>
        /// <returns>返回读取得到的结果（十六进制数）或者返回结束代码</returns>
        public async Task<string> Read_CIOAreaAsync(int BeginAdr, int ReadCount, string UnitNO = "00")
        {
            try
            {
                string EndCodeContent = null;
                string ResponseData = null;
                List<byte> CommandFrame = new List<byte> { 0x40 };
                List<byte> ResponseFrame = new List<byte>();
                List<byte> ResponseDataFrame = new List<byte>();
                CommandFrame.AddRange(ASCIIEncoding.ASCII.GetBytes(UnitNO));
                CommandFrame.AddRange(CmodeHeaderCode.HeaderCode_RR);
                //增加读取地址
                CommandFrame.AddRange(Int_D4String_ByteList(BeginAdr));
                //增加读取内容
                CommandFrame.AddRange(Int_D4String_ByteList(ReadCount));
                //增加结束符，完成命令报文
                CommandFrame.AddRange(HostLinkCore.HostLinkEndCode(CommandFrame));

                //获取回复报文
                ResponseFrame = await HostLinkCore.HostLinkCommCoreAsync(serialPort, CommandFrame);

                //获取结束代码
                EndCodeContent = CmodeEndCode.CatchEndCode(ResponseFrame, 5);
                if (EndCodeContent.Equals("00"))
                {
                    ResponseDataFrame = ResponseFrame.GetRange(7, ResponseFrame.Count - 11);
                    ResponseData = ASCIIEncoding.ASCII.GetString(ResponseDataFrame.ToArray());
                    return ResponseData;
                }
                else
                {
                    return EndCodeContent;
                }
            }
            catch (Exception)
            {
                throw;
            }
        }


        /// <summary>
        /// 读取DM内存区域（异步方法）
        /// </summary>
        /// <param name="BeginAdr">读取开始地址值（十进制）</param>
        /// <param name="ReadCount">读取的数量（十进制）</param>
        /// <param name="UnitNO">单元号（00—32）</param>
        /// <returns>返回读取得到的结果（十六进制数）或者返回结束代码</returns>
        public async Task<string> Read_DMAreaAsync(int BeginAdr, int ReadCount, string UnitNO = "00")
        {
            try
            {
                string EndCodeContent = null;
                string ResponseData = null;
                List<byte> CommandFrame = new List<byte> { 0x40 };
                List<byte> ResponseFrame = new List<byte>();
                List<byte> ResponseDataFrame = new List<byte>();
                CommandFrame.AddRange(ASCIIEncoding.ASCII.GetBytes(UnitNO));
                CommandFrame.AddRange(CmodeHeaderCode.HeaderCode_RD);
                //增加读取地址
                CommandFrame.AddRange(Int_D4String_ByteList(BeginAdr));
                //增加读取内容
                CommandFrame.AddRange(Int_D4String_ByteList(ReadCount));
                //增加结束符，完成命令报文
                CommandFrame.AddRange(HostLinkCore.HostLinkEndCode(CommandFrame));

                //获取回复报文
                ResponseFrame = await HostLinkCore.HostLinkCommCoreAsync(serialPort, CommandFrame);

                //获取结束代码
                EndCodeContent = CmodeEndCode.CatchEndCode(ResponseFrame, 5);
                if (EndCodeContent.Equals("00"))
                {
                    ResponseDataFrame = ResponseFrame.GetRange(7, ResponseFrame.Count - 11);
                    ResponseData = ASCIIEncoding.ASCII.GetString(ResponseDataFrame.ToArray());
                    return ResponseData;
                }
                else
                {
                    return EndCodeContent;
                }
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 写入CIO内存区域（异步方法）
        /// </summary>
        /// <param name="BeginAdr">读取开始地址值（十进制）</param>
        /// <param name="WriteData">写入的数值（十六进制）</param>
        /// <param name="UnitNO">单元号（00—32）</param>
        /// <returns>返回结束代码</returns>
        public async Task<string> Write_CIOAreaAsync(int BeginAdr, string WriteData, string UnitNO = "00")
        {
            try
            {
                string EndCodeContent = null;
                List<byte> CommandFrame = new List<byte> { 0x40 };
                List<byte> ResponseFrame = new List<byte>();
                CommandFrame.AddRange(ASCIIEncoding.ASCII.GetBytes(UnitNO));
                CommandFrame.AddRange(CmodeHeaderCode.HeaderCode_WR);
                //增加读取地址
                CommandFrame.AddRange(Int_D4String_ByteList(BeginAdr));
                if (WriteData != string.Empty && WriteData != null)
                {
                    //增加写入内容
                    CommandFrame.AddRange(ASCIIEncoding.ASCII.GetBytes(WriteData));
                }
                else
                {
                    throw new Exception("未输入数值");
                }
                //增加结束符，完成命令报文
                CommandFrame.AddRange(HostLinkCore.HostLinkEndCode(CommandFrame));

                //获取回复报文
                ResponseFrame = await HostLinkCore.HostLinkCommCoreAsync(serialPort, CommandFrame);

                //获取结束代码
                EndCodeContent = CmodeEndCode.CatchEndCode(ResponseFrame, 5);
                return EndCodeContent;
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 写入DM内存区域（异步方法）
        /// </summary>
        /// <param name="BeginAdr">读取开始地址值（十进制）</param>
        /// <param name="WriteData">写入的数值（十六进制）</param>
        /// <param name="UnitNO">单元号（00—32）</param>
        /// <returns>返回结束代码</returns>
        public async Task<string> Write_DMAreaAsync(int BeginAdr, string WriteData, string UnitNO = "00")
        {
            try
            {
                string EndCodeContent = null;
                List<byte> CommandFrame = new List<byte> { 0x40 };
                List<byte> ResponseFrame = new List<byte>();
                CommandFrame.AddRange(ASCIIEncoding.ASCII.GetBytes(UnitNO));
                CommandFrame.AddRange(CmodeHeaderCode.HeaderCode_WD);
                //增加读取地址
                CommandFrame.AddRange(Int_D4String_ByteList(BeginAdr));
                if (WriteData != string.Empty && WriteData != null)
                {
                    //增加写入内容
                    CommandFrame.AddRange(ASCIIEncoding.ASCII.GetBytes(WriteData));
                }
                else
                {
                    throw new Exception("未输入数值");
                }
                //增加结束符，完成命令报文
                CommandFrame.AddRange(HostLinkCore.HostLinkEndCode(CommandFrame));

                //获取回复报文
                ResponseFrame = await HostLinkCore.HostLinkCommCoreAsync(serialPort, CommandFrame);

                //获取结束代码
                EndCodeContent = CmodeEndCode.CatchEndCode(ResponseFrame, 5);
                return EndCodeContent;
            }
            catch (Exception)
            {
                throw;
            }
        }



        #endregion

    }
}
